package easier.webrtc;

import android.content.Context;
import androidx.core.util.Pair;
import java.util.ArrayList;
import java.util.List;
import org.webrtc.AudioSource;
import org.webrtc.AudioTrack;
import org.webrtc.BuiltinAudioDecoderFactoryFactory;
import org.webrtc.BuiltinAudioEncoderFactoryFactory;
import org.webrtc.Camera1Enumerator;
import org.webrtc.CameraEnumerationAndroid.CaptureFormat;
import org.webrtc.CameraEnumerator;
import org.webrtc.CameraVideoCapturer.CameraEventsHandler;
import org.webrtc.DataChannel;
import org.webrtc.DefaultVideoDecoderFactory;
import org.webrtc.DefaultVideoEncoderFactory;
import org.webrtc.EglBase;
import org.webrtc.IceCandidate;
import org.webrtc.MediaConstraints;
import org.webrtc.MediaStream;
import org.webrtc.PeerConnection;
import org.webrtc.PeerConnection.IceServer;
import org.webrtc.PeerConnectionFactory;
import org.webrtc.PeerConnectionFactory.InitializationOptions;
import org.webrtc.RtpReceiver;
import org.webrtc.SdpObserver;
import org.webrtc.SessionDescription;
import org.webrtc.SurfaceTextureHelper;
import org.webrtc.SurfaceViewRenderer;
import org.webrtc.VideoCapturer;
import org.webrtc.VideoSource;
import org.webrtc.VideoTrack;

public class WebRtcManager {

    private PeerConnectionFactory mPeerConnectionFactory;
    private MediaStream mMediaStream;
    private PeerConnection mPeerConnection;

    public void createMedia( Context context, SurfaceViewRenderer viewRenderer ) {

        /* openGL ES */
        EglBase.Context eglBaseContext = EglBase.create().getEglBaseContext();

        /* 初始化SurfaceViewRenderer */
        viewRenderer.init( eglBaseContext, null );

        /* 创建PeerConnection辅助类 */
        createPeerConnectionFactory( context, eglBaseContext );

        /* 初始化渲染 */
        SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.create( configSurfaceThreadName(), eglBaseContext );

        /* 初始化相机 */
        Camera1Enumerator enumerator = new Camera1Enumerator( false );
        final String[] deviceNames = enumerator.getDeviceNames();
        Pair< String, CaptureFormat > pair = configVideoCapturer( enumerator, deviceNames );

        /* 初始化视频 */
        VideoCapturer videoCapturer = enumerator.createCapturer( pair.first, createCameraEventsHandler() );
        VideoSource videoSource = mPeerConnectionFactory.createVideoSource( videoCapturer.isScreencast()/* 是否是屏幕截图 */ );
        videoCapturer.initialize( surfaceTextureHelper, context.getApplicationContext(), videoSource.getCapturerObserver() );
        videoCapturer.startCapture( pair.second.width, pair.second.height, pair.second.framerate.min /* 宽度,高度,帧率 */ );

        /* 捕捉视频 */
        VideoTrack videoTrack = mPeerConnectionFactory.createVideoTrack( configVideoId(), videoSource );
        videoTrack.addSink( viewRenderer );

        /* 捕捉音频 */
        AudioSource audioSource = mPeerConnectionFactory.createAudioSource( new MediaConstraints() );
        AudioTrack audioTrack = mPeerConnectionFactory.createAudioTrack( configAudioId(), audioSource );

        /* 将捕捉的媒体信息添加到媒体流 */
        mMediaStream = mPeerConnectionFactory.createLocalMediaStream( "mediaStream" );
        mMediaStream.addTrack( videoTrack );
        mMediaStream.addTrack( audioTrack );
    }

    public void createPeerConnection( PeerSignalingBridge bridge ) {

        /* 创建p2p连接 */
        List< IceServer > iceServers = provideIceServers();
        mPeerConnection = mPeerConnectionFactory.createPeerConnection( iceServers,
            new SimplePeerConnectionObserver() {
                @Override
                public void onIceCandidate( IceCandidate iceCandidate ) {

                    super.onIceCandidate( iceCandidate );
                    bridge.onIceCandidateCreated( iceCandidate );
                }

                @Override
                public void onAddStream( MediaStream mediaStream ) {

                    super.onAddStream( mediaStream );

                    /* 收到了对面客户端的媒体流,展示该媒体流 */
                    VideoTrack remoteVideoTrack = mediaStream.videoTracks.get( 0 );
                    bridge.onVideoTrackReceived( remoteVideoTrack );
                }
            } );

        /* 添加本地媒体流到通道 */
        if ( mPeerConnection != null ) {
            mPeerConnection.addStream( mMediaStream );
            bridge.mWebRtcManager = this;
        }
    }

    public static abstract class PeerSignalingBridge {

        private WebRtcManager mWebRtcManager;

        public void createOffer() {

            mWebRtcManager.mPeerConnection.createOffer( new SimpleSdpObserver() {
                @Override
                public void onCreateSuccess( SessionDescription sessionDescription ) {

                    super.onCreateSuccess( sessionDescription );

                    /* 1.创建offer成功,发送给信令服务器转发,远程客户端回调#onOfferReceived */
                    mWebRtcManager.mPeerConnection.setLocalDescription( new SimpleSdpObserver(), sessionDescription );

                    /* 通知创建offer成功 */
                    SdpModel model = new SdpModel( sessionDescription.type.canonicalForm(), sessionDescription.description );
                    onOfferCreated( model );
                }
            }, new MediaConstraints() );
        }

        public abstract void onOfferCreated( SdpModel offerData );

        public void createAnswer( SdpModel offerData ) {

            /* 2.设置对面客户端的会话信息 */
            mWebRtcManager.mPeerConnection.setRemoteDescription( new SimpleSdpObserver(),
                new SessionDescription( SessionDescription.Type.OFFER, offerData.sdp ) );
            /* 2.返回响应answer */
            mWebRtcManager.mPeerConnection.createAnswer( new SimpleSdpObserver() {
                @Override
                public void onCreateSuccess( SessionDescription sdp ) {

                    super.onCreateSuccess( sdp );
                    /* 2.设置本地会话信息 */
                    mWebRtcManager.mPeerConnection.setLocalDescription( new SimpleSdpObserver(), sdp );

                    /* 通知创建offer成功 */
                    SdpModel model = new SdpModel( sdp.type.canonicalForm(), sdp.description );
                    onAnswerCreated( model );
                }
            }, new MediaConstraints() );
        }

        public abstract void onAnswerCreated( SdpModel answerData );

        public void onAnswerReceived( SdpModel model ) {

            mWebRtcManager.mPeerConnection.setRemoteDescription( new SimpleSdpObserver(),
                new SessionDescription( SessionDescription.Type.ANSWER, model.sdp ) );
        }

        public abstract void onIceCandidateCreated( IceCandidate iceCandidate );

        public void onIceCandidateReceived( IceCandidate data ) {
            /* 对面客户端发送来内网穿透数据,保存到本地通道里 */
            mWebRtcManager.mPeerConnection.addIceCandidate( data );
        }

        public abstract void onVideoTrackReceived( VideoTrack remoteVideoTrack );
    }


    public static class SdpModel {

        public String type;
        public String sdp;

        public SdpModel( String type, String sdp ) {

            this.type = type;
            this.sdp = sdp;
        }
    }

    /**
     * 创建peer连接的工厂类,初始化{@link #mPeerConnectionFactory}
     *
     * @param context        context
     * @param eglBaseContext context
     */
    private synchronized void createPeerConnectionFactory( Context context, EglBase.Context eglBaseContext ) {

        if ( mPeerConnectionFactory != null ) {
            return;
        }

        InitializationOptions initializationOptions = InitializationOptions.builder( context.getApplicationContext() )
            .createInitializationOptions();
        PeerConnectionFactory.initialize( initializationOptions );
        PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();

        /* 视频解码 */
        DefaultVideoEncoderFactory defaultVideoEncoderFactory = new DefaultVideoEncoderFactory( eglBaseContext, true, true );
        DefaultVideoDecoderFactory defaultVideoDecoderFactory = new DefaultVideoDecoderFactory( eglBaseContext );

        /* 音频解码 */
        BuiltinAudioDecoderFactoryFactory audioDecoderFactoryFactory = new BuiltinAudioDecoderFactoryFactory();
        BuiltinAudioEncoderFactoryFactory audioEncoderFactoryFactory = new BuiltinAudioEncoderFactoryFactory();

        /* p2p连接 */
        mPeerConnectionFactory = PeerConnectionFactory.builder()
            .setOptions( options )
            .setVideoEncoderFactory( defaultVideoEncoderFactory )
            .setVideoDecoderFactory( defaultVideoDecoderFactory )
            .setAudioEncoderFactoryFactory( audioEncoderFactoryFactory )
            .setAudioDecoderFactoryFactory( audioDecoderFactoryFactory )
            .createPeerConnectionFactory();
    }

    /**
     * @return 配置音频id
     */
    protected String configAudioId() {

        return "101";
    }

    /**
     * @return 配置视频id
     */
    protected String configVideoId() {

        return "102";
    }

    /**
     * @return 配置渲染线程id
     */
    protected String configSurfaceThreadName() {

        return "SurfaceThread-1";
    }

    /**
     * 返回配置的相机和相机使用的录制参数:宽度,高度,帧率
     *
     * @param cameraEnumerator 获取相机参数
     * @param deviceNames      所有相机
     *
     * @return 选取的相机参数
     */
    protected Pair< String, CaptureFormat > configVideoCapturer( CameraEnumerator cameraEnumerator, String[] deviceNames ) {

        for ( String deviceName : deviceNames ) {
            if ( cameraEnumerator.isFrontFacing( deviceName ) ) {
                List< CaptureFormat > formats = cameraEnumerator.getSupportedFormats( deviceName );
                return new Pair<>( deviceName, formats.get( 0 ) );
            }
        }

        /* 没有前置的摄像头,使用后置的 */
        for ( String deviceName : deviceNames ) {
            if ( !cameraEnumerator.isFrontFacing( deviceName ) ) {
                List< CaptureFormat > formats = cameraEnumerator.getSupportedFormats( deviceName );
                return new Pair<>( deviceName, formats.get( 0 ) );
            }
        }

        return null;
    }

    /**
     * @return 配置相机行为
     */
    protected CameraEventsHandler createCameraEventsHandler() {

        return null;
    }

    /**
     * @return 提供ice服务器候选项
     */
    protected List< IceServer > provideIceServers() {

        ArrayList< IceServer > iceServers = new ArrayList<>();
        iceServers.add( PeerConnection.IceServer.builder( "stun:stun.l.google.com:19302" ).createIceServer() );
        return iceServers;
    }

    public static class SimplePeerConnectionObserver implements PeerConnection.Observer {

        @Override
        public void onSignalingChange( PeerConnection.SignalingState signalingState ) {

        }

        @Override
        public void onIceConnectionChange( PeerConnection.IceConnectionState iceConnectionState ) {

        }

        @Override
        public void onIceConnectionReceivingChange( boolean b ) {

        }

        @Override
        public void onIceGatheringChange( PeerConnection.IceGatheringState iceGatheringState ) {

        }

        @Override
        public void onIceCandidate( IceCandidate iceCandidate ) {

        }

        @Override
        public void onIceCandidatesRemoved( IceCandidate[] iceCandidates ) {

        }

        @Override
        public void onAddStream( MediaStream mediaStream ) {

        }

        @Override
        public void onRemoveStream( MediaStream mediaStream ) {

        }

        @Override
        public void onDataChannel( DataChannel dataChannel ) {

        }

        @Override
        public void onRenegotiationNeeded() {

        }

        @Override
        public void onAddTrack( RtpReceiver rtpReceiver, MediaStream[] mediaStreams ) {

        }
    }

    public static class SimpleSdpObserver implements SdpObserver {

        @Override
        public void onCreateSuccess( SessionDescription sessionDescription ) {

        }

        @Override
        public void onSetSuccess() {

        }

        @Override
        public void onCreateFailure( String s ) {

        }

        @Override
        public void onSetFailure( String s ) {

        }
    }
}
